﻿
using GameFramework;
using GameFramework.DataTable;
using GameFramework.Sound;
using UnityGameFramework.Runtime;
using LS.Entity;
using System;
using LS.DataTable;
using UnityEngine;

namespace LS
{
    public static class SoundExtension
    {
        private const float FadeVolumeDuration = 1f;
        private static int? s_MusicSerialId = null;

        public static int? PlayMusic(this SoundComponent soundComponent, int musicId, object userData = null)
        {
            soundComponent.StopMusic();

            var setting = LSEntry.LSBase.m_DataTableDefaultSetting;
            Type musicDataType = setting.MusicDataType;
            DataTableBase dtMusic = LSEntry.DataTable.GetDataTable(musicDataType);
            IMusicData drMusic = dtMusic.GetDataRowObject(musicId) as IMusicData;
            if (drMusic == null)
            {
                Log.Warning("Can not load music '{0}' from data table.", musicId.ToString());
                return null;
            }

            PlaySoundParams playSoundParams = PlaySoundParams.Create();
            playSoundParams.Priority = 64;
            playSoundParams.Loop = true;
            playSoundParams.VolumeInSoundGroup = 1f;
            playSoundParams.FadeInSeconds = FadeVolumeDuration;
            playSoundParams.SpatialBlend = 0f;
            s_MusicSerialId = soundComponent.PlaySound($"{LSPath.LSAssetsDirectoryName}/{LSPath.LSMusicAssetPath}/{drMusic.AssetName}", "Music", Constant.AssetPriority.MusicAsset, playSoundParams, null, userData);
            return s_MusicSerialId;
        }

        public static void StopMusic(this SoundComponent soundComponent)
        {
            if (!s_MusicSerialId.HasValue)
            {
                return;
            }

            soundComponent.StopSound(s_MusicSerialId.Value, FadeVolumeDuration);
            s_MusicSerialId = null;
        }

        public static int? PlaySound(this SoundComponent soundComponent, int soundId, EntityBase bindingEntity = null, object userData = null)
        {
            var setting = LSEntry.LSBase.m_DataTableDefaultSetting;
            Type soundDataType = setting.SoundDataType;
            DataTableBase dtSound = LSEntry.DataTable.GetDataTable(soundDataType);
            ISoundData drSound = dtSound.GetDataRowObject(soundId) as ISoundData;
            if (drSound == null)
            {
                Log.Warning("Can not load sound '{0}' from data table.", soundId.ToString());
                return null;
            }

            PlaySoundParams playSoundParams = PlaySoundParams.Create();
            playSoundParams.Priority = drSound.Priority;
            playSoundParams.Loop = drSound.Loop;
            playSoundParams.VolumeInSoundGroup = drSound.Volume;
            playSoundParams.SpatialBlend = drSound.SpatialBlend;
            return soundComponent.PlaySound($"{LSPath.LSAssetsDirectoryName}/{LSPath.LSSoundsAssetPath}/{drSound.AssetName}", "Sound", Constant.AssetPriority.SoundAsset, playSoundParams, bindingEntity != null ? bindingEntity.Entity : null, userData);
        }

        public static int? PlaySound(this SoundComponent soundComponent, int soundId, Vector3 worldPosition = default, object userData = null)
        {
            var setting = LSEntry.LSBase.m_DataTableDefaultSetting;
            Type soundDataType = setting.SoundDataType;
            DataTableBase dtSound = LSEntry.DataTable.GetDataTable(soundDataType);
            ISoundData drSound = dtSound.GetDataRowObject(soundId) as ISoundData;
            if (drSound == null)
            {
                Log.Warning("Can not load sound '{0}' from data table.", soundId.ToString());
                return null;
            }

            PlaySoundParams playSoundParams = PlaySoundParams.Create();
            playSoundParams.Priority = drSound.Priority;
            playSoundParams.Loop = drSound.Loop;
            playSoundParams.VolumeInSoundGroup = drSound.Volume;
            playSoundParams.SpatialBlend = drSound.SpatialBlend;
            return soundComponent.PlaySound($"{LSPath.LSAssetsDirectoryName}/{LSPath.LSSoundsAssetPath}/{drSound.AssetName}", "Sound", Constant.AssetPriority.SoundAsset, playSoundParams, worldPosition, userData);
        }

        public static int? PlayUISound(this SoundComponent soundComponent, int uiSoundId, object userData = null)
        {
            var setting = LSEntry.LSBase.m_DataTableDefaultSetting;
            Type soundDataType = setting.UISoundDataType;
            DataTableBase dtUISound = LSEntry.DataTable.GetDataTable(soundDataType);
            IUISoundData drSound = dtUISound.GetDataRowObject(uiSoundId) as IUISoundData;
            if (drSound == null)
            {
                Log.Warning("Can not load UI sound '{0}' from data table.", uiSoundId.ToString());
                return null;
            }

            PlaySoundParams playSoundParams = PlaySoundParams.Create();
            playSoundParams.Priority = drSound.Priority;
            playSoundParams.Loop = false;
            playSoundParams.VolumeInSoundGroup = drSound.Volume;
            playSoundParams.SpatialBlend = 0f;
            return soundComponent.PlaySound($"{LSPath.LSAssetsDirectoryName}/{LSPath.LSUISoundAssetPath}/{drSound.AssetName}", "UISound", Constant.AssetPriority.UISoundAsset, playSoundParams, userData);
        }

        public static bool IsMuted(this SoundComponent soundComponent, string soundGroupName)
        {
            if (string.IsNullOrEmpty(soundGroupName))
            {
                Log.Warning("Sound group is invalid.");
                return true;
            }

            ISoundGroup soundGroup = soundComponent.GetSoundGroup(soundGroupName);
            if (soundGroup == null)
            {
                Log.Warning("Sound group '{0}' is invalid.", soundGroupName);
                return true;
            }

            return soundGroup.Mute;
        }

        public static void Mute(this SoundComponent soundComponent, string soundGroupName, bool mute)
        {
            if (string.IsNullOrEmpty(soundGroupName))
            {
                Log.Warning("Sound group is invalid.");
                return;
            }

            ISoundGroup soundGroup = soundComponent.GetSoundGroup(soundGroupName);
            if (soundGroup == null)
            {
                Log.Warning("Sound group '{0}' is invalid.", soundGroupName);
                return;
            }

            soundGroup.Mute = mute;
            string settingName = $"Setting.{soundGroupName}Muted";
            LSEntry.Setting.SetBool(settingName, mute);
            LSEntry.Setting.Save();
        }

        public static float GetVolume(this SoundComponent soundComponent, string soundGroupName)
        {
            if (string.IsNullOrEmpty(soundGroupName))
            {
                Log.Warning("Sound group is invalid.");
                return 0f;
            }

            ISoundGroup soundGroup = soundComponent.GetSoundGroup(soundGroupName);
            if (soundGroup == null)
            {
                Log.Warning("Sound group '{0}' is invalid.", soundGroupName);
                return 0f;
            }

            return soundGroup.Volume;
        }

        public static void SetVolume(this SoundComponent soundComponent, string soundGroupName, float volume)
        {
            if (string.IsNullOrEmpty(soundGroupName))
            {
                Log.Warning("Sound group is invalid.");
                return;
            }

            ISoundGroup soundGroup = soundComponent.GetSoundGroup(soundGroupName);
            if (soundGroup == null)
            {
                Log.Warning("Sound group '{0}' is invalid.", soundGroupName);
                return;
            }

            soundGroup.Volume = volume;
            string settingName = $"Setting.{soundGroupName}Volume";
            LSEntry.Setting.SetFloat(settingName, volume);
            LSEntry.Setting.Save();
        }
    }
}
